package com.ctvit.breadking.news.task.service.impl;

import cn.hutool.http.HttpUtil;
import com.ctvit.breadking.news.core.solr.config.SolrConfig;
import com.ctvit.breadking.news.core.solr.repository.SolrDocumentRepository;
import com.ctvit.breadking.news.core.solr.utils.SolrQueryUtils;
import com.ctvit.breadking.news.task.pojo.entity.HttpLogEntity;
import com.ctvit.breadking.news.task.pojo.vo.HttpLogVO;
import com.ctvit.breadking.news.task.pojo.vo.StatVO;
import com.ctvit.breadking.news.task.service.TaskService;
import com.ctvit.breadking.news.website.pojo.vo.WebsiteVO;
import com.ctvit.breadking.news.website.service.WebsiteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.LBHttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.ctvit.breadking.news.core.constant.CommonConstant.FIELD_CREATE_TIME;
import static com.ctvit.breadking.news.core.solr.utils.SolrQueryUtils.SOLR_QUERY_ALL;

@Slf4j
@Service
public class TaskServiceImpl implements TaskService {

    private final SolrConfig solrConfig;

    private final SolrDocumentRepository solrDocumentRepository;

    private final WebsiteService websiteService;

    public TaskServiceImpl(SolrConfig solrConfig, SolrDocumentRepository solrDocumentRepository, WebsiteService websiteService) {
        this.solrConfig = solrConfig;
        this.solrDocumentRepository = solrDocumentRepository;
        this.websiteService = websiteService;
    }

    private void addHttpLogSolrDocument(WebsiteVO websiteVO) {
        String url = websiteVO.getUrl();
        long requestTime = System.currentTimeMillis();
        String requestBody = "EMPTY";
        String responseBody = "EMPTY";

        responseBody = getWebDriverRequestBody(url);
//        responseBody = getHttpRequestBody(url);

        long responseTime = System.currentTimeMillis();
        SolrInputDocument solrDocument = assignHttpLogElement(websiteVO, HttpMethod.GET.name(), requestBody, responseBody, requestTime, responseTime);
        solrDocumentRepository.add(HttpLogEntity.COLLECTION_HTTP_LOG, solrDocument.getFieldValue(HttpLogEntity.FIELD_ID).toString(), solrDocument);
    }

    private String getWebDriverRequestBody(String url) {
        WebDriver driver = null;
        try {
            ChromeOptions options = new ChromeOptions();
            options.setPageLoadStrategy(PageLoadStrategy.EAGER);
            // 只在Linux非root用户下需要
            options.addArguments("--no-sandbox");
            // 如果需要无头模式
            options.addArguments("--headless");
            options.addArguments("--remote-allow-origins=*");
            options.addArguments("--remote-debugging-port=9222");
            driver = new ChromeDriver(options);
            driver.get(url);
            return driver.getPageSource();
        } catch (Exception e) {
            log.error("请求网页异常, url:[{}]", url, e);
        } finally {
            if (Objects.nonNull(driver)) {
                driver.quit();
            }
        }
        return "EMPTY";
    }

    private String getHttpRequestBody(String url) {
        return HttpUtil.get(url);
    }

    private SolrInputDocument assignHttpLogElement(WebsiteVO websiteVO, String requestMethod, String requestBody, String responseBody, long requestTime, long responseTime) {
        SolrInputDocument solrDocument = new SolrInputDocument();
        solrDocument.addField(HttpLogEntity.FIELD_ID, websiteVO.getCode() + "_" + System.currentTimeMillis());
        solrDocument.addField(HttpLogEntity.FIELD_CODE, websiteVO.getCode());
        solrDocument.addField(HttpLogEntity.FIELD_NAME, websiteVO.getName());
        solrDocument.addField(HttpLogEntity.FIELD_URL, websiteVO.getUrl());
        solrDocument.addField(HttpLogEntity.FIELD_REQUEST_METHOD, requestMethod);
        solrDocument.addField(HttpLogEntity.FIELD_REQUEST_BODY, requestBody);
        solrDocument.addField(HttpLogEntity.FIELD_REQUEST_TIME, requestTime);
        solrDocument.addField(HttpLogEntity.FIELD_RESPONSE_BODY, responseBody);
        solrDocument.addField(HttpLogEntity.FIELD_RESPONSE_TIME, responseTime);
        solrDocument.addField(FIELD_CREATE_TIME, new Date());
        return solrDocument;
    }

    @Override
    public boolean execute() {
        List<WebsiteVO> websiteList = websiteService.list();
        for (WebsiteVO websiteVO : websiteList) {
            addHttpLogSolrDocument(websiteVO);
        }
        return false;
    }

    @Override
    public boolean execute(String code) {
        List<WebsiteVO> websiteList = websiteService.list();
        for (WebsiteVO websiteVO : websiteList) {
            if (Objects.equals(code, websiteVO.getCode())) {
                addHttpLogSolrDocument(websiteVO);
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean deleteHttpLog(String id) {
        return solrDocumentRepository.deleteById(HttpLogEntity.COLLECTION_HTTP_LOG, id);
    }

    @Override
    public List<HttpLogVO> listHttpLog() {
        List<HttpLogVO> records = Collections.emptyList();

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery(SOLR_QUERY_ALL);
        solrQuery.setFields(
                HttpLogEntity.FIELD_ID,
                HttpLogEntity.FIELD_CODE,
                HttpLogEntity.FIELD_NAME,
                HttpLogEntity.FIELD_URL,
                HttpLogEntity.FIELD_REQUEST_METHOD,
                HttpLogEntity.FIELD_REQUEST_TIME,
                HttpLogEntity.FIELD_RESPONSE_TIME,
                FIELD_CREATE_TIME
        );
        solrQuery.addSort(FIELD_CREATE_TIME, SolrQuery.ORDER.desc);

        LBHttpSolrClient lbHttpSolrClient = solrConfig.buildLbHttpSolrClient(HttpLogEntity.COLLECTION_HTTP_LOG);
        QueryResponse response = solrDocumentRepository.query(lbHttpSolrClient, solrQuery);
        SolrDocumentList queryResults = response.getResults();
        if (CollectionUtils.isNotEmpty(queryResults)) {
            records = new ArrayList<>(queryResults.size());

            for (SolrDocument queryResult : queryResults) {
                HttpLogVO httpLogVO = assignHttpLogVO(queryResult);
                records.add(httpLogVO);
            }
        }
        return records;
    }

    @Override
    public HttpLogVO getHttpLog(String id) {
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery("id:" + id);

        LBHttpSolrClient lbHttpSolrClient = solrConfig.buildLbHttpSolrClient(HttpLogEntity.COLLECTION_HTTP_LOG);
        QueryResponse response = solrDocumentRepository.query(lbHttpSolrClient, solrQuery);
        SolrDocumentList queryResults = response.getResults();
        if (CollectionUtils.isNotEmpty(queryResults)) {
            return assignHttpLogEntity(queryResults.get(0));
        }
        return new HttpLogVO();
    }

    @Override
    public StatVO statHttpLog(String code) {
        StatVO statVO = new StatVO();

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery("code:" + code);
        solrQuery.setFields(
                HttpLogEntity.FIELD_ID,
                HttpLogEntity.FIELD_CODE,
                HttpLogEntity.FIELD_NAME,
                HttpLogEntity.FIELD_URL,
                HttpLogEntity.FIELD_REQUEST_METHOD,
                HttpLogEntity.FIELD_REQUEST_TIME,
                HttpLogEntity.FIELD_RESPONSE_TIME,
                FIELD_CREATE_TIME
        );
        solrQuery.addSort(FIELD_CREATE_TIME, SolrQuery.ORDER.desc);
        solrQuery.setRows(100);

        LBHttpSolrClient lbHttpSolrClient = solrConfig.buildLbHttpSolrClient(HttpLogEntity.COLLECTION_HTTP_LOG);
        QueryResponse response = solrDocumentRepository.query(lbHttpSolrClient, solrQuery);
        SolrDocumentList queryResults = response.getResults();
        if (CollectionUtils.isNotEmpty(queryResults)) {
            int times = queryResults.size();
            long minDuration = -1L;
            long maxDuration = 0L;
            long totalDuration = 0L;
            long avgDuration;
            for (SolrDocument queryResult : queryResults) {
                HttpLogVO httpLogVO = assignHttpLogVO(queryResult);
                Long duration = httpLogVO.getDuration();

                if (Objects.equals(-1L, minDuration)) {
                    minDuration = duration;
                } else {
                    minDuration = Math.min(minDuration, duration);
                }
                maxDuration = Math.max(maxDuration, duration);
                totalDuration += httpLogVO.getDuration();

                if (Objects.equals(0L, duration)) {
                    log.info("duration is 0L, httpLogVO:[{}]", httpLogVO);
                }
            }
            avgDuration = totalDuration / times;

            statVO.setTimes(times);
            statVO.setMinDuration(minDuration);
            statVO.setMaxDuration(maxDuration);
            statVO.setTotalDuration(totalDuration);
            statVO.setAvgDuration(avgDuration);
        }

        return statVO;
    }

    private HttpLogVO assignHttpLogEntity(SolrDocument solrDocument) {
        HttpLogVO httpLogVO = assignHttpLogVO(solrDocument);
        httpLogVO.setRequestBody(SolrQueryUtils.obtainStringValue(solrDocument, HttpLogEntity.FIELD_REQUEST_BODY));
        httpLogVO.setResponseBody(SolrQueryUtils.obtainStringValue(solrDocument, HttpLogEntity.FIELD_RESPONSE_BODY));
        return httpLogVO;
    }

    private HttpLogVO assignHttpLogVO(SolrDocument solrDocument) {
        HttpLogVO httpLogVO = new HttpLogVO();
        httpLogVO.setId(SolrQueryUtils.obtainStringValue(solrDocument, HttpLogEntity.FIELD_ID));
        httpLogVO.setCode(SolrQueryUtils.obtainStringValue(solrDocument, HttpLogEntity.FIELD_CODE));
        httpLogVO.setName(SolrQueryUtils.obtainStringValue(solrDocument, HttpLogEntity.FIELD_NAME));
        httpLogVO.setUrl(SolrQueryUtils.obtainStringValue(solrDocument, HttpLogEntity.FIELD_URL));
        httpLogVO.setRequestMethod(SolrQueryUtils.obtainStringValue(solrDocument, HttpLogEntity.FIELD_REQUEST_METHOD));
        httpLogVO.setCreateTime(SolrQueryUtils.obtainDateValue(solrDocument, FIELD_CREATE_TIME));

        Long requestTime = SolrQueryUtils.obtainLongValue(solrDocument, HttpLogEntity.FIELD_REQUEST_TIME);
        Long responseTime = SolrQueryUtils.obtainLongValue(solrDocument, HttpLogEntity.FIELD_RESPONSE_TIME);
        httpLogVO.setRequestTime(requestTime);
        httpLogVO.setResponseTime(responseTime);
        httpLogVO.setDuration(responseTime - requestTime);
        return httpLogVO;
    }

}
